package cn.fansunion.leecode.math;

import java.util.Arrays;

/**
 * 976. 三角形的最大周长 给定由一些正数（代表长度）组成的数组 nums ，返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。 <br/>
 * 如果不能形成任何面积不为零的三角形，返回 0。 https://leetcode-cn.com/problems/largest-perimeter-triangle/
 * 
 * @author wen.lei@brgroup.com
 *
 *         2022-2-26
 */
public class LargestPerimeterTriangle {
    /*示例 1：
    
    输入：nums = [2,1,2]
    输出：5
    示例 2：
    
    输入：nums = [1,2,1]
    输出：0
     
    
    提示：
    3 <= nums.length <= 104
    1 <= nums[i] <= 106*/
    /**
     * 排列组合，Cn3，符合“两边之和大于第三边”求和，维护最大的和
     * 思考： 
     * 疑惑1：   “两边之和大于第三边” 可以推导出“两边之差小于第三边”吗？a+b>c，c-a<b,c-b<a，无法直接推出a-b<c。
     * （但是，b+c>a，也是肯定存在的，任意两边之和大于第三边。因此，三角形的2个规则，满足1个，另外1个自然就满足了，需要严格推理...）
     * 疑惑2：三角形3边关系，两边之和，两边之差，这2个条件都必须满足吗？还是说，满足了1个，另外1个自然就满足了。
     * 但是，官方的解法，只判断了2个较短的边 > 最长的边。道理可能是这么个道理，问题是：推理过程呢？
     * 这道题的本质不就变成了：数学中三角形的三边关系，2个基本规则，再加上本题可以知道的最长边，怎么简化判断条件吗？。
     * @param nums
     * @return
     */
    
    public int largestPerimeter(int[] nums) {
        // 自带的，从小到大
        Arrays.sort(nums);
        //3个数，都从大到小，满足3个条件的第1个就是最大周长
        for (int i = nums.length - 1; i >= 2; i--) {
            /* for (int j = nums.length-1; j >= 0; j--) {
                for (int k = nums.length-1; k >= 0; k--) {
                    final boolean threeDifNum = i != j && i != k && j != k;
                    final boolean sumLimit =
                        (nums[i] + nums[j] > nums[k]) && (nums[i] + nums[k] > nums[j]) && (nums[j] + nums[k] > nums[i]);
                    final boolean subLimit =
                        (nums[i] - nums[j] < nums[k]) && (nums[i] - nums[k] < nums[j]) && (nums[j] - nums[k] < nums[i]);
                    if (threeDifNum && sumLimit && subLimit) {
                        return nums[i] + nums[j] + nums[k];
                    }
                }
            }*/
            //两边之和，两边之差，据分析，可以互相推导
            //只用关心两边之和的情况下，排序后，相对顺序有了，c>=b>=a，满足条件的第1个就是了
            //这行表达式是对3个for循环内层2个for循环的简化，规律就是这么客观存在的
            //因此本题，本质是个数学中三角形的推理题
            final boolean sumLimit = (nums[i-1] + nums[i-2] > nums[i]);
            if(sumLimit) {
                return  nums[i-1] + nums[i-2] + nums[i];
            }
        }
        return 0;
    }

    public int largestPerimeterNotGood2(int[] nums) {
        // 自带的，从小到大
        Arrays.sort(nums);
        //3个数，都从大到小，满足3个条件的第1个就是最大周长
        for (int i = nums.length - 1; i >= 0; i--) {
            for (int j = nums.length-1; j >= 0; j--) {
                for (int k = nums.length-1; k >= 0; k--) {
                    final boolean threeDifNum = i != j && i != k && j != k;
                    final boolean sumLimit =
                        (nums[i] + nums[j] > nums[k]) && (nums[i] + nums[k] > nums[j]) && (nums[j] + nums[k] > nums[i]);
                    final boolean subLimit =
                        (nums[i] - nums[j] < nums[k]) && (nums[i] - nums[k] < nums[j]) && (nums[j] - nums[k] < nums[i]);
                    if (threeDifNum && sumLimit && subLimit) {
                        return nums[i] + nums[j] + nums[k];
                    }
                }
            }
        }
        return 0;
    }

    // 穷举，超时了，并且少了一个条件“两边之差小于第三边”
    public int largestPerimeterNotGood(int[] nums) {
        int max = 0;
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums.length; j++) {
                for (int k = 0; k < nums.length; k++) {
                    if (i != j && i != k && j != k && (nums[i] + nums[j] > nums[k]) && (nums[i] + nums[k] > nums[j])
                        && (nums[j] + nums[k] > nums[i])) {
                        max = Math.max(max, nums[i] + nums[j] + nums[k]);
                    }
                }
            }
        }
        return max;
    }
}
